from __future__ import annotations

from abc import ABC, abstractmethod

from model import Settings, Request


class Migrator(ABC):
    @abstractmethod
    def migrate(self, settings: Settings, requests: list[Request]) -> list[Request]:
        pass

    @classmethod
    def list_types(cls) -> list[str]:
        return ["v1-to-v2"]

    @classmethod
    def from_type(cls, typ: str) -> Migrator:
        match typ:
            case "v1-to-v2":
                return MigratorV1()
            case _:
                raise ValueError(f"Unknown migrator type: {typ}")


class MigratorV1(Migrator):
    """
    This migrator handles migration for version 1 requests.
    """

    def migrate(self, settings: Settings, requests: list[Request]) -> list[Request]:
        """
        In V1, requests that have identical `start` may have different `time`. However, V2 says
        that requests with identical `start` must also have identical `time`. Therefore, we need
        to migrate the requests by grouping them by `start` and assigning a proper `time` for each
        group.
        """
        migrated_requests: list[Request] = []
        start_to_time: dict[int, int] = {}
        for request in requests:
            if request.start not in start_to_time:
                start_to_time[request.start] = request.time
            migrated_requests.append(
                Request(
                    settings,
                    request.addr,
                    request.size,
                    request.start,
                    start_to_time[request.start],
                )
            )
        return migrated_requests
